package org.jsola.hr.service.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.BeanKit;
import org.jsola.common.DateKit8;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.ContractStatusEnum;
import org.jsola.hr.constant.FileType;
import org.jsola.hr.dto.EmpPaperContractImportDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpPaperContractDO;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.service.IEmpPaperContractService;
import org.jsola.hr.vo.EmpPaperContractExcelVO;
import org.jsola.hr.vo.excel.ParseResultVO;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Slf4j
public class EmpPaperContractListener extends BaseAnalysisEventListener<EmpPaperContractImportDTO> {

    /**
     * 公司ID
     */
    protected String companyId;

    /**
     * 导入结果VO
     */
    protected EmpPaperContractExcelVO empPaperContractExcelVO;

    /**
     * 达到最大值后入库
     */
    private static final Integer MAX_COUNT = 2000;

    /**
     * 入库
     */
    @Override
    public void saveData() {
        log.info("{}条数据，开始存储数据库！", dataList.size());
        if (dataList.size() == 0) {
            log.warn("没有数据需要入库");
            return;
        }
        empPaperContractExcelVO = new EmpPaperContractExcelVO();
        //成功导入列表
        List<EmpPaperContractImportDTO> importSucList = new ArrayList<>();
        //失败导入列表
        List<EmpPaperContractImportDTO> importFailList = new ArrayList<>();
        for (int i = 0; i < dataList.size(); i++) {
            EmpPaperContractImportDTO empPaperContractImportDTO = dataList.get(i);
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getStartTimeStr())) {
                try {
                    String stringValue = empPaperContractImportDTO.getStartTimeStr().replaceAll("/", "-");
                    String[] dateArray = stringValue.split("-");

                    if (dateArray.length == 3) {
                        String year = dateArray[0];
                        String month = dateArray[1];
                        if (month.length() < 2) {
                            month = "0" + month;
                        }
                        String day = dateArray[2];
                        if (day.length() < 2) {
                            day = "0" + day;
                        }
                        String date = year + "-" + month + "-" + day;
                        empPaperContractImportDTO.setStartTime(DateKit8.parseDate(date));
                    } else {
                        empPaperContractImportDTO.setReason("合同开始时间：格式有误");
                        empPaperContractImportDTO.setField("startTime");
                        importFailList.add(empPaperContractImportDTO);
                        continue;
                    }
                } catch (Exception e) {
                    empPaperContractImportDTO.setReason("合同开始时间：格式有误");
                    empPaperContractImportDTO.setField("startTime");
                    importFailList.add(empPaperContractImportDTO);
                    continue;
                }
            }
            // 无固定期限劳动合同的结束时间、合同期限置空
            if (FileType.LABORCONTRACTUNLIMIT.getValue().equals(empPaperContractImportDTO.getType())) {
                empPaperContractImportDTO.setEndTimeStr(null);
                empPaperContractImportDTO.setTermStr(null);
            }
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getEndTimeStr())) {
                try {
                    String stringValue = empPaperContractImportDTO.getEndTimeStr().replaceAll("/", "-");
                    String[] dateArray = stringValue.split("-");

                    if (dateArray.length == 3) {
                        String year = dateArray[0];
                        String month = dateArray[1];
                        if (month.length() < 2) {
                            month = "0" + month;
                        }
                        String day = dateArray[2];
                        if (day.length() < 2) {
                            day = "0" + day;
                        }
                        String date = year + "-" + month + "-" + day;
                        empPaperContractImportDTO.setEndTime(DateKit8.parseDate(date));
                    } else {
                        empPaperContractImportDTO.setReason("合同结束时间：格式有误");
                        empPaperContractImportDTO.setField("endTime");
                        importFailList.add(empPaperContractImportDTO);
                        continue;
                    }
                } catch (Exception e) {
                    empPaperContractImportDTO.setReason("合同结束时间：格式有误");
                    empPaperContractImportDTO.setField("endTime");
                    importFailList.add(empPaperContractImportDTO);
                    continue;
                }
                // 合同有开始结束时间 则开始时间不能大于结束时间
                if (empPaperContractImportDTO.getStartTime() != null && empPaperContractImportDTO.getStartTime().getTime()
                        > empPaperContractImportDTO.getEndTime().getTime()) {
                    empPaperContractImportDTO.setReason("合同结束时间：合同结束时间需大于等于合同开始时间");
                    empPaperContractImportDTO.setField("endTime");
                    importFailList.add(empPaperContractImportDTO);
                    continue;
                }
            }
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getRemarks()) && empPaperContractImportDTO.getRemarks().length() > 255) {
                empPaperContractImportDTO.setReason("合同备注：字数超过255字符");
                empPaperContractImportDTO.setField("remark");
                importFailList.add(empPaperContractImportDTO);
                continue;
            }
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getNumber()) && empPaperContractImportDTO.getNumber().length() > 50) {
                empPaperContractImportDTO.setReason("合同编号：字数超过50字符");
                empPaperContractImportDTO.setField("number");
                importFailList.add(empPaperContractImportDTO);
                continue;
            }
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getSubscribeTimeStr())) {
                try {
                    String stringValue = empPaperContractImportDTO.getSubscribeTimeStr().replaceAll("/", "-");
                    String[] dateArray = stringValue.split("-");

                    if (dateArray.length == 3) {
                        String year = dateArray[0];
                        String month = dateArray[1];
                        if (month.length() < 2) {
                            month = "0" + month;
                        }
                        String day = dateArray[2];
                        if (day.length() < 2) {
                            day = "0" + day;
                        }
                        String date = year + "-" + month + "-" + day;
                        empPaperContractImportDTO.setSubscribeTime(DateKit8.parseDate(date));
                    } else {
                        empPaperContractImportDTO.setReason("合同签订日期：格式有误");
                        empPaperContractImportDTO.setField("subscribeTime");
                        importFailList.add(empPaperContractImportDTO);
                        continue;
                    }
                } catch (Exception e) {
                    empPaperContractImportDTO.setReason("合同签订日期：格式有误");
                    empPaperContractImportDTO.setField("subscribeTime");
                    importFailList.add(empPaperContractImportDTO);
                    continue;
                }
            }
            ParamException.notNull(empPaperContractImportDTO.getIdCard(), "解析excel出错，第{" + i + 3 + "}行身份证号未输入");
            IEmpInfoService empInfoService = BeanKit.getBean(IEmpInfoService.class);
            EmpInfoDO empInfoDO = empInfoService.selectEmpByIdCard(companyId, empPaperContractImportDTO.getIdCard(), tokenUser);
            if (empInfoDO == null) {
                empPaperContractImportDTO.setReason("员工不存在");
                empPaperContractImportDTO.setField("empId");
                importFailList.add(empPaperContractImportDTO);
                continue;
            }
            IEmpPaperContractService empPaperContractService = BeanKit.getBean(IEmpPaperContractService.class);
            EmpPaperContractDO empPaperContractDO = empPaperContractImportDTO.to(EmpPaperContractDO.class);
            empPaperContractDO.setEmpId(empInfoDO.getId());
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getTermStr())) {
                try {
                    if (empPaperContractImportDTO.getTermStr().contains("年")) {
                        int parseInt = Integer
                                .parseInt(empPaperContractImportDTO.getTermStr().replace("年", ""));
                        empPaperContractDO.setTimeLimit(parseInt);
                        empPaperContractDO.setTimeLimitType(1);
                        if (empPaperContractDO.getEndTime() == null && empPaperContractDO.getStartTime() != null) {
                            Date date = DateKit8.addMonths(empPaperContractDO.getStartTime(), parseInt * 12L);
                            empPaperContractDO.setEndTime(DateKit8.addDays(date, -1));
                        }
                    } else if (empPaperContractImportDTO.getTermStr().contains("月")) {
                        int parseInt = Integer.parseInt(empPaperContractImportDTO.getTermStr().replace("月", ""));
                        empPaperContractDO.setTimeLimit(parseInt);
                        empPaperContractDO.setTimeLimitType(2);
                        // 结束日期计算补全
                        if (empPaperContractDO.getEndTime() == null && empPaperContractDO.getStartTime() != null) {
                            Date date = DateKit8.addMonths(empPaperContractDO.getStartTime(), parseInt);
                            empPaperContractDO.setEndTime(DateKit8.addDays(date, -1));
                        }
                    } else if (empPaperContractImportDTO.getTermStr().contains("日")) {
                        int parseInt = Integer
                                .parseInt(empPaperContractImportDTO.getTermStr().replace("日", ""));
                        empPaperContractDO.setTimeLimit(parseInt);
                        empPaperContractDO.setTimeLimitType(3);
                        // 结束日期计算补全
                        if (empPaperContractDO.getEndTime() == null && empPaperContractDO.getStartTime() != null) {
                            empPaperContractDO.setEndTime(DateKit8.addDays(empPaperContractDO.getStartTime(), -1));
                        }
                    } else {
                        log.error("花名册批量导入合同：" + empPaperContractImportDTO.getEmpName() + "的电子合同的合同期限有误："
                                + empPaperContractImportDTO.getTermStr());
                        empPaperContractImportDTO.setReason("合同期限：格式有误");
                        empPaperContractImportDTO.setField("termDay");
                        importFailList.add(empPaperContractImportDTO);
                        continue;
                    }
                } catch (NumberFormatException e) {
                    empPaperContractImportDTO.setReason("合同期限：格式有误");
                    empPaperContractImportDTO.setField("termDay");
                    importFailList.add(empPaperContractImportDTO);
                    continue;
                }
            }
            // 根据合同开始时间和结束时间 设置合同状态
            Integer contractStatus = empPaperContractService.getStatus(empPaperContractDO.getStartTime(), empPaperContractDO.getEndTime());
            empPaperContractDO.setStatus(contractStatus);
            // 合同名称最多80字符
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getName()) && empPaperContractImportDTO.getName().length() > 80) {
                empPaperContractImportDTO.setReason("合同名称：最多80字符");
                empPaperContractImportDTO.setField("name");
                importFailList.add(empPaperContractImportDTO);
                continue;
            }
            // 合同公司名称最多100字符
            if (StringUtils.isNotBlank(empPaperContractImportDTO.getCompanyName())
                    && empPaperContractImportDTO.getCompanyName().length() > 100) {
                empPaperContractImportDTO.setReason("合同公司：合同公司名称长度不能超过100");
                empPaperContractImportDTO.setField("companyName");
                importFailList.add(empPaperContractImportDTO);
                continue;
            }
            empPaperContractDO.setCompanyId(companyId);
            if (StringUtil.isBlank(empPaperContractDO.getName())) {
                empPaperContractDO.setName("未命名合同");
            }
            empPaperContractService.save(empPaperContractDO, tokenUser.getSiteId(), tokenUser.getUserId());
            importSucList.add(empPaperContractImportDTO);
        }
        empPaperContractExcelVO.setImportAllList(dataList);
        empPaperContractExcelVO.setImportSucList(importSucList);
        empPaperContractExcelVO.setImportFailList(importFailList);
        log.info("存储数据库成功！");
    }


    @Override
    public void onException(Exception exception, AnalysisContext context) {
        ParseResultVO<EmpPaperContractImportDTO> parseResultVO = new ParseResultVO<>();
        // 当前行号
        int row = context.readRowHolder().getRowIndex();
        // 解析是否成功
        parseResultVO.setSuccess(Boolean.FALSE);
        // 设置出错信息
        parseResultVO.setMsgList(Collections.singletonList(exception.getMessage()));
        if (parseOnly) {
            parseResultList.add(parseResultVO);
        } else {
            if (!force) {
                log.error("解析excel出错，第" + (row + 1) + "行", exception);
                if (exception instanceof ExcelDataConvertException) {
                    ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;

                    log.error("第{}行，第{}列解析异常,异常信息：{}", excelDataConvertException.getRowIndex(),
                            excelDataConvertException.getColumnIndex(), excelDataConvertException.getMessage());
                    throw new ParamException("解析excel出错，第" + (row + 1) + "行，第"
                            + (excelDataConvertException.getColumnIndex() + 1) + "列【 "
                            + excelDataConvertException.getCellData().getStringValue() + " 】 格式错误");
                }
                throw new ParamException("第" + (row + 1) + "行:" + exception.getMessage());
            } else {
                log.warn("忽略错误，解析excel出错，第" + (row + 1) + "行", exception);
            }
        }
    }

    @Override
    public void invoke(EmpPaperContractImportDTO empPaperContractImportDTO, AnalysisContext context) {
        // 获取行的索引
        log.info("解析到一条数据:{}", JSON.toJSONString(empPaperContractImportDTO));
        dataList.add(empPaperContractImportDTO);
        if (dataList.size() >= MAX_COUNT) {
            // 入库
            saveData();
            // 存储完成清理 list
            dataList.clear();
        }
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        if (context.readRowHolder().getRowIndex() == 1) {
            // 验证EXCEL表头对应名称
            List<String> stringList = new ArrayList<>();
            stringList.add("身份证号");
            stringList.add("姓名");
            stringList.add("合同编号");
            stringList.add("合同类型");
            stringList.add("合同期限");
            stringList.add("合同开始时间");
            stringList.add("合同结束时间");
            stringList.add("合同公司");
            stringList.add("合同状态");
            stringList.add("合同签订日期");
            stringList.add("合同备注");

            // 必填表头
            List<String> necessaryList = new ArrayList<>();
            necessaryList.add("身份证号");

            // 模板中的所有表头
            List<String> headList = new ArrayList<>(16);
            for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
                if (!stringList.contains(entry.getValue())) {
                    throw new ParamException("导入的员工合同模板不正确，错误表头：" + entry.getValue());
                }
                headList.add(entry.getValue());
            }
            String headException = necessaryList.parallelStream().filter(head
                    -> !headList.contains(head)).collect(Collectors.joining(","));
            ParamException.isTrue(StringUtils.isEmpty(headException), "出错了！缺少必填表头：" + headException);
        }
    }

    public String getCompanyId() {
        return companyId;
    }

    public void setCompanyId(String companyId) {
        this.companyId = companyId;
    }

    public EmpPaperContractExcelVO getEmpPaperContractExcelVO() {
        return empPaperContractExcelVO;
    }

    public void setEmpPaperContractExcelVO(EmpPaperContractExcelVO empPaperContractExcelVO) {
        this.empPaperContractExcelVO = empPaperContractExcelVO;
    }

}
